package com.dal.gm_api;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;

import com.dal.gm_api.msg.HttpRpcRequest;
import com.dal.gm_api.msg.HttpRpcResponse;
import com.dal.gm_api.util.SerializationUtils;

/**
 * @author : DengYing
 * @CreateDate : 2018年1月8日 上午10:24:32
 * @Description ：Please describe this document
 */
public class HttpRemote {

	private String url = "";

	public HttpRemote(String url) {
		super();
		this.url = url;
	}

//	public static void main(String[] args) {
//		HttpRemote r = new HttpRemote("http://127.0.0.1:7070");
//		TestImp k = r.create(TestImp.class);
////		System.out.println(k.ping("okokok"));
//		System.out.println(k.ping2("okokok"));
////		System.out.println(k.ping3("okokok"));
//		
////		Date date = new Date();
////		String json = JSON.toJSONString(date, SerializerFeature.UseISO8601DateFormat);
//////		String json = JSON.toJSONBytes(date, features)
////		Date d = JSON.parseObject(json,Date.class);
////		System.out.println(d);
//	}

	/**
	 * 
	 * @param interfaceClass
	 * @param method
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public <T> T create(final Class<?> interfaceClass) {
		// 创建动态代理对象
		return ((T) Proxy.newProxyInstance(interfaceClass.getClassLoader(), new Class<?>[] { interfaceClass },
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						HttpRpcRequest req = new HttpRpcRequest();
						req.setRequestId(UUID.randomUUID().toString());
						req.setInterfaceName(method.getDeclaringClass().getName());
						req.setMethodName(method.getName());
						req.setParameterTypes(method.getParameterTypes());
						req.setParameters(args);

//						try {
							byte[] data = SerializationUtils.serialize(req);
							data = sendPostRequest(url, data);
							HttpRpcResponse httpRpcResponse = (HttpRpcResponse)SerializationUtils.deserialize(data);
							// 返回 RPC 响应结果
			                if (httpRpcResponse.hasException()) {
			                    throw httpRpcResponse.getException();
			                } else {
			                    return (T) httpRpcResponse.getResult();
			                }
//						} catch (Exception e) {
//							// // 回调异常处理
//							throw e.getCause();
//						}
					}
				}));
	}
	
	
	public static byte[] sendPostRequest(String reqURL, byte[] data) {  
        HttpURLConnection httpURLConnection = null;  
        OutputStream out = null; //写  
        InputStream in = null;   //读  
        try {  
            URL sendUrl = new URL(reqURL);  
            httpURLConnection = (HttpURLConnection)sendUrl.openConnection();  
            httpURLConnection.setRequestProperty("Content-Type", "binary/octet-stream");
            httpURLConnection.setDoInput(true);    		//true表示允许获得输入流,读取服务器响应的数据,该属性默认值为true  
            httpURLConnection.setDoOutput(true);   		//true表示允许获得输出流,向远程服务器发送数据,该属性默认值为false  
            httpURLConnection.setUseCaches(false); 		//禁止缓存  
            httpURLConnection.setReadTimeout(30000);    //30秒读取超时  
            httpURLConnection.setConnectTimeout(30000); //30秒连接超时  
            httpURLConnection.setRequestMethod("POST");  
            httpURLConnection.setRequestProperty("rpc", Boolean.TRUE.toString());
            out = httpURLConnection.getOutputStream();  
            out.write(data);  
            out.flush(); //发送数据  
              
              
            /** 
             * 获取HTTP响应正文 
             * @see --------------------------------------------------------------------------------------------- 
             * @see SUN提供了基于HTTP协议的框架实现,不过,这些实现类并没有在JDK类库中公开,它们都位于sun.net.www包或者其子包中 
             * @see 并且,URLConnection具体子类(HttpURLConnection类)的getInputStream()方法仅仅返回响应正文部分的输入流 
             * @see HTTP响应结果包括HTTP响应码,响应头和响应正文3部分,获得输入流后,就能读取服务器发送的响应正文 
             * @see ---------------------------------------------------------------------------------------------- 
             * @see 使用httpURLConnection.getContentLength()时,要保证服务器给返回Content-Length头属性 
             * @see byte[] byteDatas = new byte[httpURLConnection.getContentLength()]; 
             * @see httpURLConnection.getInputStream().read(byteDatas); 
             * @see respBody = new String(byteDatas, respCharset); 
             * @see ---------------------------------------------------------------------------------------------- 
             * @see in = httpURLConnection.getInputStream(); 
             * @see byte[] byteDatas = new byte[in.available()]; 
             * @see 关于InputStream.available()说明如下,更详细说明见JDK API DOC 
             * @see 有些InputStream的实现将返回流中的字节总数,但也有很多实现不会这样做 
             * @see 试图使用in.available()方法的返回值分配缓冲区,以保存此流所有数据的做法是不正确的 
             * @see ---------------------------------------------------------------------------------------------- 
             */  
            in = httpURLConnection.getInputStream();  
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();  
            byte[] buff = new byte[1024];  
            int len = -1;  
            while((len=in.read(buff)) != -1){  
                buffer.write(buff, 0, len);  
            }  
            return buffer.toByteArray();
        } catch (Exception e) {  
            System.out.println("与[" + reqURL + "]通信异常,堆栈信息如下");  
            e.printStackTrace();  
            return null;  
        } finally {  
            if (out != null) {  
                try {  
                    out.close();  
                } catch (Exception e) {  
                    System.out.println("关闭输出流时发生异常,堆栈信息如下");  
                    e.printStackTrace();  
                }  
            }  
            if (in != null) {  
                try {  
                    in.close();  
                } catch (Exception e) {  
                    System.out.println("关闭输入流时发生异常,堆栈信息如下");  
                    e.printStackTrace();  
                }  
            }  
            if (httpURLConnection != null) {  
                httpURLConnection.disconnect();  
                httpURLConnection = null;  
            }  
        }  
    }  
	
}
